package la.iok.hzsvn.lewin.movie.shopmovie.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import la.iok.hzsvn.lewin.movie.core.RoleEnum;
import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.core.model.SimpleOrgUnitVo;
import la.iok.hzsvn.lewin.movie.core.movieservice.vo.MovieLevelVo;
import la.iok.hzsvn.lewin.movie.core.shopmovie.param.CouponDefinitionListParam;
import la.iok.hzsvn.lewin.movie.core.shopmovie.param.CouponDefinitionParam;
import la.iok.hzsvn.lewin.movie.core.shopmovie.vo.CouponDefinitionVo;
import la.iok.hzsvn.lewin.movie.services.MovieServiceInvoker;
import la.iok.hzsvn.lewin.movie.services.OrgUnitIntegration;
import la.iok.hzsvn.lewin.movie.shopmovie.entity.CouponDefinition;
import la.iok.hzsvn.lewin.movie.shopmovie.mapper.CouponDefinitionMapper;
import la.iok.hzsvn.lewin.mybatis.model.PageParam;
import la.iok.hzsvn.lewin.mybatis.model.PageVo;
import la.iok.hzsvn.lewin.mybatis.model.SortParam;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.Nullable;
import la.iok.hzsvn.share.collection.IdOperators;
import la.iok.hzsvn.share.tools.exception.SystemException;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class CouponDefinitionServiceImpl extends BaseServiceImpl<CouponDefinition, CouponDefinitionMapper, Long> implements CouponDefinitionService {
    private final MovieServiceInvoker movieServiceInvoker;
    private final OrgUnitIntegration orgUnitIntegration;
    public CouponDefinitionServiceImpl(CouponDefinitionMapper mapper,
                                       MovieServiceInvoker movieServiceInvoker,
                                       OrgUnitIntegration orgUnitIntegration) {
        super(mapper);
        this.movieServiceInvoker = movieServiceInvoker;
        this.orgUnitIntegration = orgUnitIntegration;
    }

    @Override
    public Long save(@NotNull Token token, @NotNull CouponDefinitionParam param) {
        token.validAnyAuthority(RoleEnum.Admin, RoleEnum.Manager, RoleEnum.ShopManager);
        validateParam(param);
        Long orgUnitId = -1L;
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(token.getOrgUnitId() !=null && token.getOrgUnitId() > 0,"组织","用户不属于任何组织");
            validateOrgUnit(token.getOrgUnitId());
            orgUnitId = token.getOrgUnitId();
        }
        try{
            CouponDefinition entity = new CouponDefinition();
            BeanUtils.copyProperties(param, entity);
            entity.setOrgUnitId(orgUnitId);
            insertSelective(entity);
            return entity.getId();
        }catch (DuplicateKeyException e){
            throw new SystemException("名称不能重复",e);
        }
    }

    @Override
    public void modify(@NotNull Token token, @Nullable Long id, @NotNull CouponDefinitionParam param) {
        token.validAnyAuthority(RoleEnum.Admin, RoleEnum.Manager, RoleEnum.ShopManager);
        validateParam(param);
        CouponDefinition entity = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(entity, id);
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.ORG_UNIT_ACCESS_DENIED.assertEqual(entity.getOrgUnitId(), token.getOrgUnitId(), entity.getOrgUnitId());
            validateOrgUnit(entity.getOrgUnitId());
        }
        mapper.updateByParam(id, param);
    }

    @Override
    public void delete(@NotNull Token token, @Nullable Long id) {
        token.validAnyAuthority(RoleEnum.Admin, RoleEnum.Manager, RoleEnum.ShopManager);
        CouponDefinition entity = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(entity, id);
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.ORG_UNIT_ACCESS_DENIED.assertEqual(entity.getOrgUnitId(), token.getOrgUnitId(), entity.getOrgUnitId());
        }
        delete(id);
    }

    @NotNull
    @Override
    public PageVo<CouponDefinitionVo> page(@NotNull Token token, @NotNull PageParam pageParam, @NotNull SortParam sortParam,
                                           @NotNull CouponDefinitionListParam listParam) {
        token.validAnyAuthority(RoleEnum.Admin, RoleEnum.Manager, RoleEnum.ShopManager,RoleEnum.CarpoolMaster,RoleEnum.CustomerService);
        Set<Long> orgUnitIds = new HashSet<>();
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(token.getOrgUnitId()!=null && token.getOrgUnitId() > 0,
                    "组织","用户不属于任何组织");
            orgUnitIntegration.userManageOrgUnits(token, orgUnitIds);
            //全局的也可以查
            orgUnitIds.add(-1L);
        }
        String orderColumn = sortParam.orderColumn("orgUnitId");
        String order = sortParam.order();
        Page<CouponDefinition> page = PageHelper.startPage(pageParam.getPage(), pageParam.getLimit());
        mapper.listPage(orderColumn, order, orgUnitIds, listParam);
        Set<Long> orgIds = page.stream().map(CouponDefinition::getOrgUnitId).collect(Collectors.toSet());
        List<SimpleOrgUnitVo> orgUnits = movieServiceInvoker.orgUnits(orgIds);
        List<MovieLevelVo> movieLevels = movieServiceInvoker.movieLevels();
        return page(page, item->{
            CouponDefinitionVo vo = new CouponDefinitionVo();
            BeanUtils.copyProperties(item, vo);
            SimpleOrgUnitVo o = IdOperators.find(orgUnits, item.getOrgUnitId());
            if(o != null){
                vo.setOrgUnitName(o.getName());
            }else if(Objects.equals(item.getOrgUnitId(), -1L)){
                vo.setOrgUnitName("系统");
            }
            MovieLevelVo level = IdOperators.find(movieLevels, item.getMovieLevelId());
            if(level != null){
                vo.setMovieLevelName(level.getName());
            }else if(Objects.equals(item.getMovieLevelId(), -1L)){
                vo.setMovieLevelName("无限制");
            }
            return vo;
        });
    }

    private void validateParam(CouponDefinitionParam param) {
        param.setName(ErrorCode.NAME_BLANK_ERROR.assertNotBlank(param.getName()));
        ErrorCode.PROPERTY_CHECK_ERROR.assertNotNull(param.getAmount(),"数量","数量不能为空");
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(param.getAmount() > 0,"数量","数量必须是正数");
        ErrorCode.PROPERTY_CHECK_ERROR.assertAnyOf(param.getType(),new Integer[]{1,2},"类型","类型值只能是1[折扣券]或者2[金额券]");
        if(param.typePercent()){
            ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(param.getAmount()>0&&param.getAmount()<=100,"数量","折扣券范围为(0,100]");
            if(param.getMaxAmount() != null){
                ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(param.getMaxAmount() == -1 || param.getMaxAmount() > 0,"最大金额","最大金额必须大于0或者无限制");
            }
        }
    }

    private void validateOrgUnit(Long orgUnitId) {
        SimpleOrgUnitVo orgUnit = movieServiceInvoker.orgUnitInfo(orgUnitId);
        ErrorCode.ORG_UNIT_NOT_EXIST.assertNotNull(orgUnit, orgUnitId);
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(orgUnit.shopType(),"组织","组织类型必须是店铺");
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(orgUnit.normalStatus(),"店铺","店铺状态异常");
    }
}
